/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/
/**
 *
 * \file
 * \brief Cross-Platform utilities.
 * This header contains a collection of miscellaneous but very useful
 * utilities intended for easy cross-platform thread and synchronization
 * usage.
 * \author Antti Maula <antti.maula@tkk.fi>
 *
 * \todo Most of the description are still only brief. More exact
 *       documentation is required.
 */


#ifndef _GIMSRC_OWNUTILS_H_
#define _GIMSRC_OWNUTILS_H_
#include <time.h>
#include <stdio.h>
#include <inttypes.h>


#if !defined(WINDOWS_OS) & !defined(LINUX_OS)
 #error "Unsupported platform for ownutils, please specify WINDOWS_OS or LINUX_OS"
#endif

/////////// GENERIC - PLATFORM INDEPENDENT ////////////////
// Own status
#define ownStatus                 int
#define ownStatusOK               0
#define ownStatusTimeout          -1
#define ownStatusBusy             -2
#define ownStatusError            -66
#define ownStatusUnknown          -666
#define ownStatusUnimplemented    -6666

// STL helps
#define EACH_IN_i(x)            __typeof__((x).begin()) i = (x).begin(); i != (x).end(); ++i
#define EACH_IN_j(x)            __typeof__((x).begin()) j = (x).begin(); j != (x).end(); ++j
#define EACH_IN_k(x)            __typeof__((x).begin()) k = (x).begin(); k != (x).end(); ++k
#define EACH_IN_l(x)            __typeof__((x).begin()) l = (x).begin(); l != (x).end(); ++l
#define ITERATOR(x)             __typeof__( (x).begin() )
#define REVERSE_ITERATOR(x)     __typeof__( (x).rbegin() )

// Bitwise helps, x is the variable, y is the flag to set | test.
# define OWNFLAG_SET(x, y) ((x) = (x) | (y))
# define OWNFLAG_UNSET(x, y) ((x) = (x) & (~(y)))
# define OWNFLAG_ISSET(x, y) ((x) & (y))

// If not defined, define MIN / MAX functions as fast macros.
#ifndef MIN
# define MIN(a, b) (((a)<(b))?(a):(b))
#endif

#ifndef MAX
# define MAX(a, b) (((a)>(b))?(a):(b))
#endif

#ifndef DEG2RAD
# define DEG2RAD(deg) ((deg)*(M_PI/180.0))
#endif

#ifndef RAD2DEG
# define RAD2DEG(rad) ((rad)*(180.0/M_PI))
#endif

// Common THREAD defines
#define ownThreadCancelStateEnable    1  ///< Cancelling thread is enabled
#define ownThreadCancelStateDisable   0  ///< Cancelling thread is disabled
#define ownThreadCancelTypeDeferred   1  ///< Cancellation type deferred
#define ownThreadCancelTypeAsync      2  ///< Cancellation type async (NOW!)

// Common typedef for handling time replies.
typedef long long int ownTime_ms_t;          // 64 bits, unsigned
typedef long long int ownTime_ms_delta_t;    // 64 bits, signed


// Platform specific defines
#if defined( WINDOWS_OS )
  #include <windows.h>
  #include <string.h>
  #include <stdio.h>
  #include <stdlib.h>

  int random();
  void srand(unsigned seed);


  typedef HANDLE ownSemHandle;
  typedef HANDLE ownCondHandle;
  typedef HANDLE ownMutexHandle;
  typedef HANDLE ownThreadHandle;

  #define ownMutexHandleInitializer NULL
  #define ownMutexHandleNullInitializer NULL
  #define ownCondHandleNullInitializer (reinterpret_cast<HANDLE>(NULL))
  #define ownThreadHandleNullInitializer (reinterpret_cast<HANDLE>(NULL))

  #define SIGTERM 0
#elif defined ( LINUX_OS )

  #include <pthread.h>
  #include <signal.h>
  #include <stdio.h>
  #include <unistd.h>
  #include <stdlib.h>
  #include <strings.h>
  #include <string.h>
  #include <sys/time.h>
  #include <semaphore.h>

  #include <errno.h>

  // Providing a prototype!
  int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);

  typedef sem_t * ownSemHandle;
  typedef pthread_cond_t * ownCondHandle;
  typedef pthread_mutex_t * ownMutexHandle;
  typedef pthread_t * ownThreadHandle;

#ifdef __cplusplus
  #define ownThreadHandleNullInitializer (reinterpret_cast<pthread_t *>(NULL))
  #define ownMutexHandleInitializer (reinterpret_cast<pthread_mutex_t *>(NULL)) // Deprecated
  #define ownMutexHandleNullInitializer (reinterpret_cast<pthread_mutex_t *>(NULL))
  #define ownCondHandleNullInitializer (reinterpret_cast<pthread_cond_t *>(NULL))
#else
  #define ownThreadHandleNullInitializer ((pthread_t *)(NULL))
  #define ownMutexHandleInitializer ((pthread_mutex_t *)(NULL)) // Deprecated
  #define ownMutexHandleNullInitializer ((pthread_mutex_t *)(NULL))
  #define ownCondHandleNullInitializer ((pthread_cond_t *)(NULL))
#endif

#else
#endif

#ifdef __cplusplus
extern "C" {
#endif

  /** Sleep in millisecond precision.
   *
   * Sleeps for specified time in milliseconds.
   * @param[in] t_ms            Time to sleep in milliseconds
   */
  void ownSleep_ms(const ownTime_ms_t t_ms);


  /** Sleep in microsecond precision.
   *
   * Sleeps for specified time in microseconds.
   *
   * @param[in] t_us            Time to sleep in microseconds
   */
  void ownSleep_us(const ownTime_ms_t t_us);


  /** Initialize ownRandom based on current time.
   *
   * This function initializes the ownRandom engine based on current
   * time. gettimeofday function is used for microsecond precision to
   * prevent processes starting at the same time from getting same
   * random sequences.
   *
   * \note The values are still _PSEUDO_ random, hence they are always
   * predictable and not suitable for security applications.
   */
  void ownRandom_init_time();


  /** Get a random value between min and max.
   *
   * This function returns a pseudorandom float value in specified
   * range.
   *
   * \note The values are _PSEUDO_ random, hence they are always
   * predictable and not suitable for security applications.
   *
   * @param[in] min             Minimum limit to return.
   * @param[in] max             Maximum limit to return.
   * @return                    Float value between given min and max.
   */
  float ownRandom_get_range(const float min, const float max);


  /** Get a random unsigned long int value between specified min and max.
   *
   * This function returns a pseudorandom integer value from given
   * range, inclusive.
   *
   * \note The values are _PSEUDO_ random, hence they are always
   * predictable and not suitable for security applications.
   *
   * @param[in] min             Minimum limit to return.
   * @param[in] max             Maximum limit to return.
   * @return                    'long int' value between given min and max.
   */
  long int ownRandom_get_l_int(const long int min,
                               const long int max);
  

  /** Reset ownTime starting point.
   *
   * This function sets a new starting point for time functions. This
   * starting point is used as a starting point for various library
   * functions, for example: ownTime_get_ms() will return ~zero if
   * called right after calling this method.
   */
  void ownTime_Reset(void);


  /** Return the current time in seconds and microseconds.
   *
   * Returns the current time since 1.1.1970.
   * @param[out] seconds       Current time since 1.1.1970 - seconds part
   * @param[out] microseconds  Time after the seconds part, in microseconds
   * @return                   OwnStatus value; whether operation was
   *                           successfull or not.
   */
  ownStatus ownTime_GetTimeOfDay(long int *seconds,
                                 long int *microseconds);

  /** Returns time in seconds (floating point vaule).
   *
   * Returns the current time since some starting point in seconds.
   * @return                    Current time in seconds since some point
   */
  double ownTime_get_s();


  /** Returns time elapsed since specified starting point in seconds.
   *
   * Returns time elapsed in seconds since the given time.
   * @param[in] since           Time to compare with
   * @return                    Time elapsed since the given time
   */
  double ownTime_get_s_since(const double since);


  /** Returns time in milliseconds (since some starting point).
   *
   * Returns the current time since some unspecified starting point in milliseconds
   * @return                    Current time in milliseconds
   */
  ownTime_ms_t ownTime_get_ms(void);


  /** Returns time elapsed since specified starting point in milliseconds.
   * @param[in] t_ms            Starting point in milliseconds
   * @return                    Time elapsed since starting point in milliseconds.
   */
  ownTime_ms_delta_t ownTime_get_ms_since(const ownTime_ms_t t_ms);


  /** Returns remaining time to limit from begin.
   *
   * This function evaluates the following:
   * 'limit - ownTime_get_ms_since(begin)'
   *
   * @param[in] limit           Limit in milliseconds to evaluate against.
   * @param[in] begin           Reference point to measure from.
   * @return                    Number of milliseconds left before the time limit
   *                            calculated from begin point to current time is
   *                            reached.
   */
  ownTime_ms_delta_t ownTime_get_ms_left(const ownTime_ms_t limit, const ownTime_ms_t begin);


  /** Case-insensitively Compare strings.
   *
   * Compares two strings case-insensitively.
   * Semantics equal to strcasecmp() function.
   *
   */
  int ownStrsEqual(const char *strA, const char *strB);


  /** Initialize a Semaphore.
   *
   */
  ownSemHandle ownSemaphore_Init(int initial, int max);


  /** Destroy a Semaphore.
   *
   */
  ownStatus ownSemaphore_Destroy(ownSemHandle handle);


  /** Get semaphore (Decrement)
   *
   */
  ownStatus ownSemaphore_Get(ownSemHandle handle, int timeout);


  /** Set Semaphore (Increment)
   *
   */
  ownStatus ownSemaphore_Put(ownSemHandle handle, int count);


  /** Init Mutex.
   *
   */
  ownMutexHandle ownMutex_Init(void);


  /** Destroy Mutex.
   *
   */
  ownStatus ownMutex_Destroy(ownMutexHandle handle);


  /** Lock Mutex.
   *
   */
  ownStatus ownMutex_Lock(ownMutexHandle handle);


  /** Try locking a mutex. If not acquired immediately; don't block at all.
   *
   */
  ownStatus ownMutex_TryLock(ownMutexHandle handle);


  /** Unlock Mutex.
   *
   */
  ownStatus ownMutex_Unlock(ownMutexHandle handle);


  /** Init Condition variable.
   *
   */
  ownCondHandle ownCond_Init(void);


  /** Destroy Condition variable.
   *
   */
  void ownCond_Destroy(ownCondHandle handle);


  /** Wait for condition.
   *
   */
  ownStatus ownCond_Wait(ownCondHandle handle, ownMutexHandle mutex, int timeout);


  /** Signal Condition.
   *
   * \warning This is not supported on Windows, it does a broadcast instead.
   */
  ownStatus ownCond_Signal(ownCondHandle handle);


  /** Broadcast Condition.
   *
   */
  ownStatus ownCond_Broadcast(ownCondHandle handle);



  /** Create new thread.
   *
   */
  ownThreadHandle ownThread_Create(void *routine, void *parameter);


  /** Join a Thread.
   *
   */
  ownStatus ownThread_Join(ownThreadHandle handle, void *return_value);


  /** Signal a thread.
   *
   */
  ownStatus ownThread_Signal(ownThreadHandle handle, int signal);


  /** Cancel a running Thread.
   *
   */
  ownStatus ownThread_Cancel(ownThreadHandle handle);


  /** Test whether a thread should cancel (Thread-cancellation point)
   *
   */
  ownStatus ownThread_TestCancel(void);


  /** Set current thread cancel state.
   *
   * Options are:
   * ownThreadCancelStateDisable
   * ownThreadCancelStateEnable
   *
   */
  ownStatus ownThread_SetCancelState(int state);


  /** Set current thread cancel type.
   *
   * Options are:
   * ownThreadCancelTypeDeferred
   * ownThreadCancelTypeAsync
   */
  ownStatus ownThread_SetCancelType(int type);

  /**
   * This function call 'Yields' the processor, releasing its remaining
   * timeslice. If there are no other processes to run, this thread can
   * continue immediately.
   *
   */
  void ownSched_Yield(void);


  /** Calculate simple and fast CRC hash.
   *
   * This function calculates a simple 32bit hash from the given data.
   * Source:\n
   * http://www.cs.hmc.edu/~geoff/classes/hmc.cs070.200101/homework10/hashfuncs.html
   * 'CRC Variant'
   *
   * @param[in] aData           Pointer to data to calculate
   * @param[in] aLen            Length of data.
   * @return                    32 bit value representing the HASH of given data.
   */
  uint32_t ownHash_SimpleCRC(const unsigned char *aData, const unsigned int aLen);


  /** Compare two floating point values.
   *
   * If they match within the given accuracy, return zero. If the A is greater,
   * return negative, if the B is greater, return positive integer.
   *
   * @param[in] aA              First floating point value to compare
   * @param[in] aB              Second floating point value to compare
   * @param[in] aAccuracy       Required accuracy. Meaning; how much  values
   *                            can differ to be interpreted as equal. Accuracy
   *                            value must be positive.
   * @return                    0 if values are considered equal, negative
   *                            when A > B, positive when A < B.
   */
  int ownCompare_Float(const float aA, const float aB, const float aAccuracy);

#ifdef __cplusplus
}
#endif

#endif //_UTILS_H_

/******************************************************************************
 *****************************************************************************/
